/***********************************************************************
 ** Reykjavik University
 ** Grímur Tómasson & Eiríkur Torfason
 ** Copyright (c) 2011. All rights reserved.
 **********************************************************************/

#include "Utility.h"

#include <limits.h>

//----------------------------------------------------------------------------------------------------------
//
// Constants for the values assigned for two and three in a row
//
const int TWO_IN_A_ROW_SCORE = 3;
const int THREE_IN_ROW_SCORE = 9;
//
// OK, don't be scared. The utility function scans each row, column and diagonal of the board to look for sequences
// of tokens of the same color. This array simply holds the indices for the cells in each column, row and diagonal.
// These scanlines are separated by a -1 (the boundary value) in the array.
// By pre-computing the indices we can scan the board in a single loop, treating the board as a stream of tokens,
// empty cells and boundaries.
//
const char lines [] = {
	0,7,14,21,28,35,42,-1,1,8,15,22,29,36,43,-1,2,9,16,23,30,37,44,-1,3,10,17,24,31,38,45,-1,4,11,18,25,32,39,46,-1,5,12,19,26,33,40,47,-1, // rows
	0,1,2,3,4,5,-1,7,8,9,10,11,12,-1,14,15,16,17,18,19,-1,21,22,23,24,25,26,-1,28,29,30,31,32,33,-1,35,36,37,38,39,40,-1,42,43,44,45,46,47,-1, // columns
	5,-1,42,-1,4,12,-1,3,11,19,-1,2,10,18,26,-1,1,9,17,25,33,-1,0,8,16,24,32,40,-1,7,15,23,31,39,47,-1,14,22,30,38,46,-1,21,29,37,45,-1,28,36,44,-1,35,43,-1, // diagonals, +y
	47,-1,0,-1,46,40,-1,45,39,33,-1,44,38,32,26,-1,43,37,31,25,19,-1,42,36,30,24,18,12,-1,35,29,23,17,11,5,-1,28,22,16,10,4,-1,21,15,9,3,-1,14,8,2,-1,7,1 // diagonals, -y
};

const int BOUNDARY_COLOR = -2;
const int EMPTY_COLOR = 0;
const int BLACK_COLOR = 1;
const int RED_COLOR = -1;

//----------------------------------------------------------------------------------------------------------
//
// This utility function looks for two or three tokens of the same color in a row, where there's an empty
// cell on either or both sides. A higher score is awarded for three in a row than two in a row. A positive
// value is awarded if the tokens belong to the current player and a negative value if the tokens belong to the
// opponent. The sum is then returned.
//
int utility( bitboard* bitboardArrayPointer[], int* currentPlyPointer, int side )
{
	//
	//Check for a win
	//
	if( hasWon( *bitboardArrayPointer[side] ) )
	{
		return INT_MAX;
	}
	if( hasWon( *bitboardArrayPointer[side^1] ) )
	{
		return INT_MIN;
	}
	//
	// Declare and initialize variables
	//
	int score = 0;  //For player 0 (black)
	int lastColor = BOUNDARY_COLOR;
	int currentColor = EMPTY_COLOR;
	int sameInARow = 1;
	int addScore = 0;
	bool preceededByEmpty = false;
	//
	// Iterate through the scanlines array. 
	// We know that it contains 204 elements...we had the Elbonians count them for us.
	//
	for( int index = 0; index < 204; ++index )
	{
		//
		// Boundary check (board edges)
		//
		if( lines[ index ] == -1 )
		{
			currentColor = BOUNDARY_COLOR;
		}
		//
		// Is there a black token in this cell?
		//
		else if ( CHECK_BIT( *bitboardArrayPointer[0], lines[index] ) )
		{
			currentColor = BLACK_COLOR;
		}
		//
		// Is there a red token in this cell?
		//
		else if( CHECK_BIT( *bitboardArrayPointer[1], lines[index] ) )
		{
			currentColor = RED_COLOR;
		}
		else 
		{
			//
			// This cell must be empty
			//
			currentColor = EMPTY_COLOR;
		}
		//
		// Does this cell have the same color as the last one?
		//
		if( currentColor == lastColor )
		{
			//
			// Increment the counter
			//
			++sameInARow;
		}
		else 
		{
			//
			// New color. Now, we don't really care if the last cell was empty since sequences of empty cells
			// don't contribute to the score.
			//
			if (lastColor != EMPTY_COLOR) 
			{
				//
				// OK, the last cell was not empty. Now we need to check whether the previous string of 
				// same-colored tokens was either preceeded or followed by an empty cell because otherwise
				// it doesn't contribute to the score.
				//
				if (preceededByEmpty == true || currentColor == EMPTY_COLOR)
				{
					//
					// We've found a sequence (of one or more) tokens with an empty cell on at least one side.
					// Update the score.
					//
					addScore = 0;
					if (sameInARow == 2)
					{
						addScore = TWO_IN_A_ROW_SCORE;
					}
					else if (sameInARow == 3)
					{
						addScore = THREE_IN_ROW_SCORE;
					}
					score += addScore * lastColor;
				}
			}
			//
			// We need to remember if the last cell was empty
			//
			preceededByEmpty = (lastColor == EMPTY_COLOR);
			//
			// Reset the counter
			//
			sameInARow = 1;
		}
		//
		// Remember the color of this cell
		//
		lastColor = currentColor;
	}
	//
	// Is red playing?
	//
	if( side == 1 )
	{
		//
		// Invert the score
		//
		score = -score;
	}
	//
	// Return the evaluation of the board
	//
	return score;	
}
//----------------------------------------------------------------------------------------------------------

